import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__),'modules'))
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)),'modules'))
from composing import TxtFormat
import ganzhi
import copy
from PIL import Image,ImageFont,ImageDraw
import PIL
from datetime import date, datetime,timedelta
import json
import random
import pandas as pd
# pd.set_option('display.unicode.ambiguous_as_wide', True)
pd.set_option('display.unicode.east_asian_width', True)
import re
from moviepy.editor import *
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.tts.v20190823 import tts_client, models
import asyncio
import json
import numpy as np
from mutagen.mp3 import MP3
import platform


def dec_print(msg):
    def decorator(func):
        def wrapper(*args,**kwargs):
            print(msg)
            return func(*args,**kwargs)
        return wrapper
    return decorator

class WeekYun:
    def __init__(self,work_dir='D:\\工作目录\\ejj'):
        self.work_dir=work_dir
        # print('weekyun:',self.work_dir)

    def read_day_cmt(self,xls='d:\\工作目录\\ejj\\运势\\运势.xlsx'):
        df_dayyun=pd.read_excel(xls,sheet_name='运势',skiprows=1)
        df_dayyun.columns=['日期','星期','干','支','导语','木颜色','木描述','火颜色','火描述','土颜色','土描述','金颜色','金描述','水颜色','水描述']
        df_dayyun['干支']=df_dayyun['干']+df_dayyun['支']
        df_dayyun=df_dayyun[['日期','星期','干支','导语','木颜色','木描述','火颜色','火描述','土颜色','土描述','金颜色','金描述','水颜色','水描述']]
        return df_dayyun

    def read_color_para(self,xls='d:\\工作目录\\ejj\\运势\\运势.xlsx'):
        df_color_para=pd.read_excel(xls,sheet_name='参数表-色系')
        return df_color_para

    def read_dec_para(self,xls='d:\\工作目录\\ejj\\运势\\运势.xlsx'):
        df_dec_para=pd.read_excel(xls,sheet_name='参数表-饰品')
        return df_dec_para

    def day_cmt(self,date_input='20220822',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx'):
        df_cmt=self.read_day_cmt(xls=xls)
        df_cmt['日期']=pd.to_datetime(df_cmt['日期'],errors='coerce')
        # print(df_cmt.iloc[915])
        day_cmt=df_cmt[df_cmt['日期']==datetime.strptime(date_input,'%Y%m%d')].copy(deep=True)
        dategz=ganzhi.GanZhi().cal_dateGZ(int(date_input[:4]),int(date_input[4:6]),int(date_input[6:]),8,0)['bazi']
  
        gz=''.join(dategz)
        day_cmt['日期干支']=gz[:2]+'年'+gz[2:4]+'月'+gz[4:6]+'日'
        return day_cmt

    def wuxing(self,date_input='20220822',wx='木',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx'):
        daycmt=self.day_cmt(date_input=date_input,xls=xls)
        df=pd.DataFrame()
        
        df['日期']=daycmt['日期']
        df['星期']=daycmt['星期']
        df['日期干支']=daycmt['日期干支']
        df['颜色']=daycmt[wx+'颜色'].str.replace(r'[，,、]','',regex=True)
        df['颜色']=df['颜色'].apply(lambda x:''.join(sorted(x.strip())))
        df['导语']=daycmt['导语']
        df['描述']=daycmt[wx+'描述']
        df['五行']=wx

        
        #色系图地址
        # print(df['颜色'].tolist()[0])
        # print(map(sorted,df['颜色'].tolist()[0]))
   
        color_list=[]
        for color in os.listdir(os.path.join(self.work_dir,'素材','色系图')):
            if color[-3:].lower()=='png':
                clr_name=color.split('_')[0]
                if ''.join(sorted(clr_name))==df['颜色'].tolist()[0]:
                    color_list.append(color)
        try:
            _pick_color=random.choice(color_list)
            
        except IndexError:
            print(color_list)
            print(df['颜色'].tolist()[0]+'：目录中没有对应的色系图片'+'\n')
            err_str=df['颜色'].tolist()[0]+'：目录中没有对应的色系图片'
            return {'res':'failed','error':err_str}
            exit(0)
        pick_color=os.path.join(self.work_dir,'素材','色系图',_pick_color)
        df['颜色图地址']=pick_color

        #色系图描述
        color_txt=self.read_color_para(xls=xls)
        color_txt['排序颜色名']=color_txt['颜色'].apply(lambda x: ''.join(sorted(x)))
        res_colors=color_txt[color_txt['排序颜色名']==df['颜色'].tolist()[0]]
        # print(df['颜色'].tolist()[0],color_txt['排序颜色名'])
        res_color=res_colors.sample(1)
        # print(res_colors,'\n\n',res_color)
        color=res_color['标签'].tolist()[0].replace('，',' ')
        df['颜色标签']=color
        df['实际颜色']=df['颜色'].tolist()[0]

        lucky_wxs=color_txt[color_txt['排序颜色名']==df['颜色'].tolist()[0]]
        # print('lucky wxs:',lucky_wxs)
        df['幸运五行']=lucky_wxs.sample(1)['五行属性'].tolist()[0]
        # print(color_txt)

        #饰品图地址
        dec_txt=self.read_dec_para(xls=xls)

        decs=[]
        for clr in df['颜色'].tolist()[0]:
            # print('df["颜色"] clr:',clr)
            if clr=='黑':
                clr='蓝'
            if clr=='金':
                clr='白'
            if clr=='银':
                clr='白'
            if clr=='粉':
                clr='红'
            if clr=='紫':
                clr='红'
            if clr=='棕':
                clr='黄'
            if clr=='粉红':
                clr='红'
            dec_wxs=dec_txt[dec_txt['颜色']==clr].sample(1)['五行属性'].tolist()[0]
            if dec_wxs not in decs:
                decs.append(dec_wxs)
        
        dec_urls=[]
        for dec_wx in decs:
            for dec_fn in os.listdir(os.path.join(self.work_dir,'素材','饰品图')):
                if dec_fn[0]==dec_wx:
                    dec_urls.append(os.path.join(self.work_dir,'素材','饰品图',dec_fn))

        df['饰品图地址']=','.join(dec_urls)

        return {'res':'ok','res_data':df}
        
class ExportImage(WeekYun):
    def __init__(self,work_dir='D:\\工作目录\\ejj'):
        self.work_dir=work_dir
        with open(os.path.join(os.path.dirname(__file__),'configs','fonts.config'),'r',encoding='utf-8') as f:
            self.config=json.load(f)        
    
    def font(self,ft_name,ft_size):
        font_fn=self.config[ft_name].replace('$',self.work_dir)
        if os.name == 'posix':  # Mac 系统
            # for key, value in font_fn.items():
            #     font_fn[key] = value.replace('\\', '/')
            font_fn=font_fn.replace('\\','/')
        return ImageFont.truetype(font_fn,ft_size)

    def font_color(self,txt):
        clist={
            "红":"#DC262B",
            "黄":"#EFF94A",
            "蓝":"#1A3E68",
            "绿":"#267B23",
            "白":"#B3B5B3",
            "黑":"#000000",
            "灰":"#474847",
            "金":"#DDD5A6"
        }

        try:
            return clist[txt]
        except:
            return clist['灰']

    def wx_color(self,wx):
        # wxlist={
        #     '木':'#99A16D',
        #     '火':'#DB3D29',
        #     '土':'#AB896E',
        #     '金':'#EEE1B1',
        #     '水':'#36475C'
        # }
        # wxlist={
        #     '木':'#91d697',
        #     '火':'#fb738c',
        #     '土':'#a77771',
        #     '金':'#FFDA1B',
        #     '水':'#00ABE5'
        # }
        wxlist={
            '木':'#71a273',
            '火':'#ff7149',
            '土':'#d19328',
            '金':'#fae467',
            '水':'#197789'
        }
        return wxlist[wx]

    def back_img(self,wx='木'):
        img=Image.open(os.path.join(self.work_dir,'素材','穿搭底图',wx+'.jpg'))
        img=img.resize((720,960))
        return img

    def dec_material(self,lucky_wx):
        wx=list(lucky_wx)
        # print('wx input:',wx)
        wx_len=len(wx)

        if wx_len==0:
            return '无有效的幸运五行'
        
        dec_dir=os.path.join(self.work_dir,'素材','饰品材料图')
        if wx_len==1:
            dec_mtrls_pics_urls=[]
            for fn in os.listdir(os.path.join(dec_dir,wx[0])):
                dec_mtrls_pics_urls.append(os.path.join(dec_dir,wx[0],fn))
            out_urls=random.sample(dec_mtrls_pics_urls,3)
        
        if wx_len==2:
            rdm_int=random.randint(1,2)
            dec_mtrls_pics_urls_0=[]
            for fn in os.listdir(os.path.join(dec_dir,wx[0])):
                dec_mtrls_pics_urls_0.append(os.path.join(dec_dir,wx[0],fn))
            out_urls=random.sample(dec_mtrls_pics_urls_0,rdm_int)

            dec_mtrls_pics_urls_1=[]
            for fn in os.listdir(os.path.join(dec_dir,wx[1])):
                dec_mtrls_pics_urls_1.append(os.path.join(dec_dir,wx[1],fn))
            out_urls.extend(random.sample(dec_mtrls_pics_urls_1,3-rdm_int))

        if wx_len>=3:
            dec_mtrls_pics_urls_0=[]
            for fn in os.listdir(os.path.join(dec_dir,wx[0])):
                dec_mtrls_pics_urls_0.append(os.path.join(dec_dir,wx[0],fn))
            out_urls=[random.choice(dec_mtrls_pics_urls_0)]

            dec_mtrls_pics_urls_1=[]
            for fn in os.listdir(os.path.join(dec_dir,wx[1])):
                dec_mtrls_pics_urls_1.append(os.path.join(dec_dir,wx[1],fn))
            out_urls.append(random.choice(dec_mtrls_pics_urls_1))

            dec_mtrls_pics_urls_2=[]
            for fn in os.listdir(os.path.join(dec_dir,wx[2])):
                dec_mtrls_pics_urls_2.append(os.path.join(dec_dir,wx[2],fn))
            out_urls.append(random.choice(dec_mtrls_pics_urls_2))

        return {'dec_material_urls':out_urls}



    def draw_img(self,date_input='20220822',wx='木',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',exp_txt='no',dec_name_only='no'):
        # print('draw_img...')
        bg_img=self.back_img(wx=wx)
        infos_wx=self.wuxing(date_input=date_input,wx=wx,xls=xls)
        if infos_wx['res']=='ok':
            infos=infos_wx['res_data']
            # print(infos.columns)
        
            #文字部分
            wxtitle=infos['五行'].tolist()[0]+'宝宝'
            weekday='星期'+infos['星期'].tolist()[0]
            date_txt=datetime.strftime(infos['日期'].tolist()[0],'%Y年%m月%d日')
            date_gz=infos['日期干支'].tolist()[0]
            color_txt=infos['颜色标签'].tolist()[0]       

            #饰品封面图
            dec_cover=self.draw_dec_cover(date_gz,date_txt,weekday)
            
            #饰品      
            # res=self.draw_decs(bg_img,infos,wxtitle,weekday,date_txt,date_gz,dec_name_only='no')
            # bg_img=res['bg_img']
            # dec_txt_out=res['res_data']
            dec_txt_out=''

          
            #色系图
            color_url=infos['颜色图地址'].tolist()[0] 
            x_colorblock,y_colorblock=290,224
            img_color=Image.open(color_url)
            img_color=img_color.resize((298,43))            
            bg_img.paste(img_color,(x_colorblock,y_colorblock))            

            
            #标题
            draw=ImageDraw.Draw(bg_img)
            draw.text((186,74),text=wxtitle,font=self.font('汉仪心海行楷W',50),fill=self.wx_color(wxtitle[0]))


            #饰品材质图      
            dec_materials_pic_urls=self.dec_material(infos['幸运五行'].tolist()[0])
            # print('材质urls：',dec_materials_pic_urls)
            dec_x,dec_y=265,382
            for url in dec_materials_pic_urls['dec_material_urls']:
                dec_img=Image.open(url)
                dec_img=dec_img.resize((60,60))
                dec_mask=dec_img.split()[3]
                # bg_img=bg_img.convert()
                bg_img.paste(dec_img,(dec_x,dec_y),dec_mask)
                dec_x+=(dec_img.size[0]+18)

            #日期
            date_x,date_y=240,760 #210,730;  
            draw.text((date_x,date_y),text=date_txt+'  '+weekday,font=self.font('字由文艺黑体',24),fill='#72726E') 
            draw.text((date_x+10,date_y+40),text=date_gz,font=self.font('字由文艺黑体',28),fill='#72726E')       

            #颜色描述
            for real_color in infos['实际颜色'].tolist()[0]:
                ft_size_colortxt=20
                x_colortxt,y_colortxt=x_colorblock+img_color.size[0]//2-(len(color_txt)*ft_size_colortxt)//2,y_colorblock+80
                draw.text((x_colortxt,y_colortxt),color_txt,font=self.font('华康海报体W12(P)',ft_size_colortxt),fill='#9E9E9D')
            
            #日运文字
            txt=infos[infos['五行']==wx]['描述'].tolist()[0]
            bg_img=self.draw_fortune_text(bg_img,txt)

            return {'res':'ok','dec_cover':dec_cover,'draw_img_data':[bg_img,dec_txt_out]}
        else:
            return {'res':'failed','error':infos_wx['error']}
    
    #日运文字
    def draw_fortune_text(self,bg_img,txt):
        # print('wuxing txt:',txt)
        draw=ImageDraw.Draw(bg_img)
        from textwrap import wrap
        lines = []
        line_height=26
        line_spacing=20
        for paragraph in txt.split('\n'):
            lines.extend(wrap(paragraph, width=20))  # 每行最多30个字符
        
        # print('txt lines:',lines)
        wt,ht=bg_img.size
        text_area_width = wt - 20  # 总宽度减去二维码和边距
        text_x = 280 
        text_y = 460  # 文字区域顶部位置
  
        for line in lines:
            if text_y + line_height > ht - 10:  # 防止超出文字区域
                break
            # draw.text((text_x, text_y+line_spacing+line_height+2), line, font=self.font('楷体',32), fill='#334455')
            # text_y += line_height + line_spacing  # 行间距
            draw.text((text_x, text_y+line_spacing+line_height+2), line[5:], font=self.font('楷体',32), fill='#334455')
            text_y += line_height + line_spacing  # 行间距
        return bg_img

    #饰品封面
    def draw_dec_cover(self,date_gz,date_txt,weekday):
        dir=os.path.join(self.work_dir,'素材','二维码饰品图片')
        fns=[]
        for fn in os.listdir(dir):
            if fn.split('.')[-1].lower()=='jpg' or fn.split('.')[-1].lower()=='jpeg' or fn.split('.')[-1].lower()=='png':
                fns.append(os.path.join(dir,fn))
        selected_dec_img=random.choice(fns)
        img=Image.open(selected_dec_img)
        img = img.resize((720, 960), Image.Resampling.LANCZOS)

        img=img.convert('RGBA')
        # 创建半透明条带
        band_height = 300  # 条带高度
        band = Image.new('RGBA', (img.size[0], band_height), (128, 128, 128, 128))
        # 添加半透明矩形（覆盖在图片中部）
        band_mask = band.split()[3]  # 获取alpha通道
        img.paste(band, (0, 50), band_mask)  # 使用alpha通道进行合成

        draw=ImageDraw.Draw(img)
        ft_size_date=64
        ft_size_gz=54
        ft_size_weekday=60

        offset_x,offset_y=4,4

        pos_date_txt=self.calculate_text_position(img,date_txt,self.font('黑体',ft_size_date))
        draw.text((pos_date_txt[0][0],100),text=date_txt,font=self.font('黑体',ft_size_date),fill='#000000') 
        draw.text((pos_date_txt[0][0]-offset_x,100-offset_y),text=date_txt,font=self.font('黑体',ft_size_date),fill='#ffffff') 

        pos_date_wd=self.calculate_text_position(img,weekday,self.font('黑体',ft_size_weekday))
        draw.text((pos_date_wd[0][0],270),text=weekday,font=self.font('黑体',ft_size_weekday),fill='#000000') 
        draw.text((pos_date_wd[0][0]-offset_x,270-offset_y),text=weekday,font=self.font('黑体',ft_size_weekday),fill='#ffffff') 

        pos_date_gz=self.calculate_text_position(img,date_gz,self.font('黑体',ft_size_gz))
        draw.text((pos_date_gz[0][0],180),text=date_gz,font=self.font('黑体',ft_size_gz),fill='#000000')   
        draw.text((pos_date_gz[0][0]-offset_x,180-offset_y),text=date_gz,font=self.font('黑体',ft_size_gz),fill='#ffffff')      

        img=img.convert('RGB')
        return img

    def calculate_text_position(self,img, text, font):
        """精确计算文本位置的核心函数"""
        # 获取文本实际渲染尺寸
        bbox = font.getbbox(text)  # 获得(left, top, right, bottom)
        text_width = bbox[2] - bbox[0]
        text_height = bbox[3] - bbox[1]
        
        # 计算居中坐标
        x = (img.width - text_width) // 2  # 水平居中
        y = 120  # 垂直位置保持原设定
        return (x, y), text_width, text_height

    #画饰品
    def draw_decs(self,bg_img,infos,wxtitle,weekday,date_txt,date_gz,dec_name_only='no'):
        _decs=infos['饰品图地址'].tolist()[0].split(',')
        random.shuffle(_decs)
        
        #去重，去类型相同的饰品，如手镯，只有一个
        decs_drop_dup=[]
        type_dup_list=[]
        for _pre_decs in _decs:
            if _pre_decs.split('_')[2] not in type_dup_list:
                decs_drop_dup.append(_pre_decs)
                type_dup_list.append(_pre_decs.split('_')[2])

        #如饰品数>3，则随机选出3个
        if len(decs_drop_dup)>3:
            decs=random.sample(decs_drop_dup,3)
        else:
            decs=decs_drop_dup


        #饰品名字文字
        dec_txts=[]
        dec_txt_out_list=[]
        for dec in decs:
            dec_txt=''
            if platform.system().lower()=='windows':
                _dec_t=dec.split('\\')[-1].split('_')
            elif platform.system().lower()=='darwin' or platform.system().lower()=='linux':
                _dec_t=dec.split('/')[-1].split('_')
            dec_txt+=_dec_t[1]+_dec_t[2]
            dec_txts.append([dec_txt,_dec_t[0]])
            dec_txt_out_list.append(dec_txt)
        
        #输出到文本的饰品描述内容
        dec_txt_out='、'.join(dec_txt_out_list)
        
        #取消文本的饰品描述
        # dec_txt_out=''

        if dec_name_only=='yes':
            return {'res':'ok','res_data':dec_txt_out}

        #url
        color_url=infos['颜色图地址'].tolist()[0]
        dec_urls=decs
        
        # print('decs:',decs)

        # print(wxtitle,weekday,date_txt,date_gz,color_txt,decs,dec_txts)
        
        #色系图
        x_colorblock,y_colorblock=290,224
        img_color=Image.open(color_url)
        img_color=img_color.resize((298,43))
        
        bg_img.paste(img_color,(x_colorblock,y_colorblock))

    #饰品图 
        x_dec,y_dec,dec_gap=270,454,50
        x_dec_txt_init=copy.deepcopy(x_dec)
        
        for dec_url in dec_urls:       
            img_dec=Image.open(dec_url)            
            img_dec=img_dec.resize((80,80))
            img_dec_a=img_dec.split()[3]
            bg_img.paste(img_dec,(x_dec,y_dec),mask=img_dec_a)
            x_dec+=(img_dec.size[0]+dec_gap)
        
        #标题
        draw=ImageDraw.Draw(bg_img)
        draw.text((120,74),text=wxtitle,font=self.font('汉仪心海行楷W',50),fill=self.wx_color(wxtitle[0]))

        #日期
        draw.text((210,730),text=date_txt+'  '+weekday,font=self.font('字由文艺黑体',24),fill='#72726E') 
        draw.text((220,770),text=date_gz,font=self.font('字由文艺黑体',28),fill='#72726E') 

        #饰品描述
        ft_size_dectxt=14
        for dec_id,dec_txt in enumerate(dec_txts):
            # print(dec_txt)
            #计算饰品描述文字坐标
            x_dec_txt,y_dec_txt=x_dec_txt_init+img_dec.size[0]*dec_id+dec_gap*dec_id+img_dec.size[0]//2-len(dec_txt[0])*ft_size_dectxt//2,y_dec+img_dec.size[1]+10
            draw.text((x_dec_txt,y_dec_txt),dec_txt[0],font=self.font('华康海报体W12(P)',ft_size_dectxt),fill=self.wx_color(dec_txt[1]))
        
        return {'bg_img':bg_img,'res_data':dec_txt}

    def batch_deal(self,prd=['20220822','20220828'],out_put_dir='e:\\temp\\ejj\\日穿搭',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx'):
        # print('batch deal img')
        stime,etime=datetime.strptime(prd[0],'%Y%m%d'),datetime.strptime(prd[1],'%Y%m%d')
        if stime>etime:
            raise CustomError('week_yun.ExportImage().batch_deal() error: 结束日小于起始日')
        
        datelist=[]
        while stime<=etime:
            datelist.append(stime.strftime('%Y%m%d'))
            stime+=timedelta(days=1)
               
        
        out_decs_txt=Vividict()
        for nowtime in datelist:
            date_dir=nowtime[:4]+'-'+nowtime[4:6]+'-'+nowtime[6:]
            save_dir=os.path.join(out_put_dir,date_dir)
            if not os.path.exists(save_dir):
                os.makedirs(save_dir)
            for num,wx in enumerate(['木','火','土','金','水']):
                # print('正在生成 '+date_dir+' '+wx+'  穿搭')
                res_draw_img_data=self.draw_img(date_input=nowtime,wx=wx,xls=xls)
                # print(wx,res_draw_img_data)
                if res_draw_img_data['res']=='ok':                    
                    if num==0:
                    #保存饰品封面，仅一次
                        dec_cover_img=res_draw_img_data['dec_cover']                    
                        dec_save_name=os.path.join(save_dir,f'00-饰品封面.jpg')
                        dec_cover_img.save(dec_save_name,quality=95,subsampling=0)

                    #保存五行运势
                    res_img,dec_txt=res_draw_img_data['draw_img_data']
                    save_name=os.path.join(save_dir,str(num+1)+'-'+wx+'.jpg')
                    res_img.save(save_name,quality=95,subsampling=0)

                    out_decs_txt[nowtime][wx]=dec_txt
                else:
                    return {'res':'failed','error':res_draw_img_data['error']}


        # print('batch deal img 完成')

        return {'res':'ok','res_data':out_decs_txt}

class ExportWeekYunTxt(ExportImage):
    def __init__(self,work_dir='D:\\工作目录\\ejj',import_dec_dic=''):
        super(ExportWeekYunTxt,self).__init__(work_dir=work_dir)
        self.import_dec_dic=import_dec_dic

    def wx_icon(self,wx='木'):
        wxchr_list={
            "木":"🌳",
            "火":"🔥",
            "土":"⛰︎",
            "金":"🗡",
            "水":"💧",
            "日历":"📅"
        }

        return wxchr_list[wx]

    def exp_txt(self,date_input='20220822',wx='木',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',desc_txt_show='yes'):
        
        infos_wx=self.wuxing(date_input=date_input,wx=wx,xls=xls)
        
        if infos_wx['res']=='ok':
            infos=infos_wx['res_data']
            
            #衣服配色语句clr_txt
            clrs=infos['颜色标签'].tolist()[0].split(' ')
            if len(clrs)==1:
                clr_txt='建议穿'+clrs[0]+'衣服，'
            elif len(clrs)==2:
                clr_txt='建议穿'+clrs[0]+'、'+clrs[1]+'衣服，'
            else:
                clr_txt='建议穿'+'、'.join(clrs[:-1])+'以及'+clrs[-1]+'衣服，'

            # print(infos['饰品图地址'].tolist()[0].split(','))
            
            
            #佩戴饰品语句dec_txt
            #无饰品语句导入
            if desc_txt_show=='yes':
                if self.import_dec_dic=='':  
                    decs=infos['饰品图地址'].tolist()[0].split(',')                
                    dec_names=[x.split('\\')[-1].split('_')[1]+x.split('\\')[-1].split('_')[2] for x in decs]
                    for dec_name in dec_names:
                        if len(dec_names)==1:
                            dec_txt='佩戴'+dec_names[0]+'等饰品。'
                        elif len(dec_names)==2:
                            dec_txt='佩戴'+dec_names[0]+'及'+dec_names[1]+'等饰品。'
                        else:
                            dec_txt='佩戴'+'、'.join(dec_names[:3])+'等饰品或'+clrs[-1]+'的饰品。'
                #有饰品语句导入
                else:   
                    dec_txt='佩戴'+self.import_dec_dic['res_data'][date_input][wx]+'或者'+clrs[-1]+'的饰品。'
            else:
                dec_txt=''


            #取消饰品描述
            dec_txt=''
            
            
            
            daycmt=self.day_cmt(date_input=date_input,xls=xls)
            # print(date_input)
            df=pd.DataFrame()        
            df['日期']=daycmt['日期']
            df['星期']=daycmt['星期']
            df['日期干支']=daycmt['日期干支']
            df['导语']=daycmt['导语']
            df['描述']=daycmt[wx+'描述']
            df['五行']=wx
            wxtitle=wx+'宝宝'

            
            
            title='【伊姐运程】'+datetime.strftime(df['日期'].tolist()[0],'%Y年%m月%d日')+'（星期'+df['星期'].tolist()[0]+'）运势|穿搭配色\n\n'+self.wx_icon('日历')+ \
                                    '  '+df['日期干支'].tolist()[0]+'\n'

            wxtxt=self.wx_icon(wx=wx)+'  '+wxtitle+clr_txt+dec_txt+'\n'+df['描述'].tolist()[0]

            return {'res':'ok','res_data':[title,wxtxt],'pre_txt':df['导语'].tolist()[0]}
        else:
            return {'res':'failed'}

    def all_wx_txt(self,date_input='20220822',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='yes',
                save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='yes',desc_txt_show='yes'):        
        all_txt=''
        
        for wx in ['木','火','土','金','水']:
            txts_res=self.exp_txt(date_input=date_input,wx=wx,xls=xls,desc_txt_show=desc_txt_show)
            # print('all_wx_txt:',all_txt)
            txts=txts_res['res_data']
            pre_txt=txts_res['pre_txt']

            #抖音内容
            dy_cover_date=txts_res['res_data'][0][6:17]
            dy_cover_wd=txts_res['res_data'][0][17:22]
            dy_page_date=txts_res['res_data'][0][6:24]
            dy_page_lunar_date=txts_res['res_data'][0][-10:-1]

            try:    
                if wx=='木':
                    dy_mu=re.findall(r'【.*',txts_res['res_data'][1])[0]
                elif wx=='火':
                    dy_huo=re.findall(r'【.*',txts_res['res_data'][1])[0]
                elif wx=='土':
                    dy_tu=re.findall(r'【.*',txts_res['res_data'][1])[0]
                elif wx=='金':
                    dy_jin=re.findall(r'【.*',txts_res['res_data'][1])[0]
                elif wx=='水':
                    dy_shui=re.findall(r'【.*',txts_res['res_data'][1])[0]
                # else:
                #     print(wx,'--找不到相描述')
            except Exception as e:
                print('生成抖音内容出错：', wx)

            all_txt+=txts[1]+'\n\n'

        # print(dy_cover_date,dy_cover_wd,dy_page_date,dy_page_lunar_date,dy_mu,dy_huo,dy_tu,dy_jin,dy_shui)
        
    
        if pre_txt is not np.nan:
            all_txt=txts[0]+'\n'+pre_txt+'\n\n'+all_txt
        else:
            all_txt=txts[0]+'\n'+'空白导语'+'\n\n'+all_txt

        if sense_word_judge=='yes':
            # print('正在处理敏感词...')
            with open(os.path.join(self.work_dir,'素材','config','敏感词.txt'),'r',encoding='utf-8') as f:
                text=f.read()
            
            lines=text.split('\n')
            sensitive_dic={}
            for line in lines:
                if line.strip():  # 忽略空行
                    key, value = line.strip().split(':')
                    sensitive_dic[key.strip().strip('"')] = value.strip().strip('",')

            for key in sensitive_dic.keys():   
                if key in all_txt:
                    all_txt=all_txt.replace(key,sensitive_dic[key])
                
        if save=='yes':
            date_dir=date_input[:4]+'-'+date_input[4:6]+'-'+date_input[6:]
            save_dir=os.path.join(save_dir,date_dir)
            if not os.path.exists(save_dir):
                os.makedirs(save_dir)

            # print(os.path.join(save_dir,date_dir+'_日运.txt'))
            with open(os.path.join(save_dir,date_dir+'_日运.txt'),'w',encoding='utf-8') as f:
                f.write(all_txt)
        
        return {'riyun_all_txt':all_txt,'douyin_txt':[dy_cover_date,dy_cover_wd,dy_page_date,dy_page_lunar_date,dy_mu,dy_huo,dy_tu,dy_jin,dy_shui]}
    

    def douyin(self,txt_lst,save_dir):
        print('正在生成抖音图片内容')
        dy_cover=Image.open(os.path.join(self.work_dir,'素材','抖音底图','抖音封面.jpg'))
        dy_page=Image.open(os.path.join(self.work_dir,'素材','抖音底图','抖音内容.jpg'))

        dy_date_cover=txt_lst[0]
        dy_week_cover=txt_lst[1]
        dy_page_title=txt_lst[2]
        dy_page_lunar=txt_lst[3]
        # dy_mu_jx=txt_lst[4][:3] if txt_lst[4][:3] else "【无吉凶判断】"
        # dy_mu=txt_lst[4][3:]
        dy_mu_jx="【无吉凶判断】"
        dy_mu=txt_lst[4][5:]
        # dy_huo_jx=txt_lst[5][:3] if txt_lst[4][:3] else "【无吉凶判断】"
        # dy_huo=txt_lst[5][3:]
        dy_huo_jx="【无吉凶判断】"
        dy_huo=txt_lst[5][5:]
        # dy_tu_jx=txt_lst[6][:3] if txt_lst[4][:3] else "【无吉凶判断】"
        # dy_tu=txt_lst[6][3:]
        dy_tu_jx="【无吉凶判断】"
        dy_tu=txt_lst[6][5:]
        # dy_jin_jx=txt_lst[6][:3] if txt_lst[4][:3] else "【无吉凶判断】"
        # dy_jin=txt_lst[7][3:]
        dy_jin_jx="【无吉凶判断】"
        dy_jin=txt_lst[7][5:]
        # dy_shui_jx=txt_lst[6][:3] if txt_lst[4][:3] else "【无吉凶判断】"
        # dy_shui=txt_lst[8][3:]
        dy_shui_jx="【无吉凶判断】"
        dy_shui=txt_lst[8][5:]


        draw_cover=ImageDraw.Draw(dy_cover)
        draw_cover.text((336,150),text=dy_date_cover,fill='#7030a0',font=self.font('黑体',110))
        draw_cover.text((444,310),text=dy_week_cover,fill='#7030a0',font=self.font('黑体',110))
        
        draw_page=ImageDraw.Draw(dy_page)
        # temp_t='木宝宝今天是高光日，各种签约单子纷至沓来，考试、跳槽、找工作都能收到好消息。更开心的是今天桃花运也很好。'
        draw_page.text((100,60),text=dy_page_title,fill='#4b11a4',font=self.font('黑体',56))
        draw_page.text((170,154),text=dy_page_lunar,fill='#4b11a4',font=self.font('黑体',54))

        #吉凶
        draw_page.text((220,298),text=dy_mu_jx,fill='#01510a',font=self.font('黑体',36))
        draw_page.text((220,618),text=dy_huo_jx,fill='#c00100',font=self.font('黑体',36))
        draw_page.text((220,942),text=dy_tu_jx,fill='#885303',font=self.font('黑体',36))
        draw_page.text((228,1260),text=dy_jin_jx,fill='#febe04',font=self.font('黑体',36))
        draw_page.text((220,1578),text=dy_shui_jx,fill='#086bbf',font=self.font('黑体',36))
        
        #描述
        TxtFormat().put_txt_img(draw=draw_page,tt=dy_mu,total_dis=956, \
                                    xy=[112,368],dis_line=28,fill='#01510a', \
                                    font_name='楷体',font_size=32,addSPC="yes")
        TxtFormat().put_txt_img(draw=draw_page,tt=dy_huo,total_dis=956, \
                                    xy=[112,688],dis_line=28,fill='#c00100', \
                                    font_name='楷体',font_size=32,addSPC="yes")
        TxtFormat().put_txt_img(draw=draw_page,tt=dy_tu,total_dis=956, \
                                    xy=[112,1008],dis_line=28,fill='#885303', \
                                    font_name='楷体',font_size=32,addSPC="yes")
        TxtFormat().put_txt_img(draw=draw_page,tt=dy_jin,total_dis=956, \
                                    xy=[112,1328],dis_line=28,fill='#febe04', \
                                    font_name='楷体',font_size=32,addSPC="yes")
        TxtFormat().put_txt_img(draw=draw_page,tt=dy_shui,total_dis=956, \
                                    xy=[112,1648],dis_line=28,fill='#086bbf', \
                                    font_name='楷体',font_size=32,addSPC="yes")
 

        #保存
        if platform.system().lower()=='windows':
            save_name_cover=os.path.join(save_dir,save_dir.split('\\')[-1]+'-抖音封面.jpg')
            dy_cover.save(save_name_cover,quality=95,subsampling=0)
            save_name_page=os.path.join(save_dir,save_dir.split('\\')[-1]+'-抖音内容.jpg')
            dy_page.save(save_name_page,quality=95,subsampling=0)
        elif platform.system().lower()=='darwin' or platform.system().lower()=='linux':
            save_name_cover=os.path.join(save_dir,save_dir.split('/')[-1]+'-抖音封面.jpg')
            dy_cover.save(save_name_cover,quality=95,subsampling=0)
            save_name_page=os.path.join(save_dir,save_dir.split('/')[-1]+'-抖音内容.jpg')
            dy_page.save(save_name_page,quality=95,subsampling=0)

        # print('完成')        

    def all_date_wx(self,prd=['20220822','20220828'],xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',
                    save='yes',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='yes',import_dec_dic='',desc_txt_show='yes'):
        stime,etime=datetime.strptime(prd[0],'%Y%m%d'),datetime.strptime(prd[1],'%Y%m%d')
        datelist=[]
        while stime<=etime:
            datelist.append(stime.strftime('%Y%m%d'))
            stime+=timedelta(days=1)
        
        res_all_txt={}
        
        for nowtime in datelist:
            # print('正在处理 '+nowtime[:4]+'-'+nowtime[4:6]+'-'+nowtime[6:]+' 穿搭配色文案')
            res=self.all_wx_txt(date_input=nowtime,xls=xls,save=save,save_dir=save_dir,sense_word_judge=sense_word_judge,desc_txt_show=desc_txt_show)
            res_all_txt[nowtime]=res['riyun_all_txt']
            self.douyin(txt_lst=res['douyin_txt'],save_dir=os.path.join(save_dir,nowtime[:4]+'-'+nowtime[4:6]+'-'+nowtime[6:]))

        print('完成')
        return {'res_all_txt':res_all_txt}
        
class videoClips(ExportWeekYunTxt):
    def __init__(self,work_dir='D:\\工作目录\\ejj',import_dec_dic='',import_txt=''):
        super(videoClips,self).__init__(work_dir=work_dir,import_dec_dic=import_dec_dic)
        self.import_txt=import_txt

    @dec_print('\n正在生成语音文本...')
    def tts_text(self,date_input='20240513',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='no',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='no'):
        if self.import_txt=='':
            origin_text=self.all_wx_txt(date_input=date_input,xls=xls,save=save,save_dir=save_dir,sense_word_judge=sense_word_judge)
            origin_text=origin_text['riyun_all_txt']
        else:
            origin_text=self.import_txt['res_all_txt'][date_input]

        print('origin text:',origin_text)

        text_arr=origin_text.split('\n\n')

        # print('text_arr:',text_arr)
        
        out_txt=[]
        if text_arr[2]!='空白导语':
            title=text_arr[0][6:22]+text_arr[1][2:]+'运势及穿搭配色。\n'+text_arr[2]
       
            out_txt.append(title)

            for txt in text_arr[3:]:
                if txt!="":
                    txt=re.sub(r'\n【.】','',txt[2:])
                    txt=re.sub(r'\n','',txt)
                    out_txt.append(txt)
        else:
            title=text_arr[0][6:22]+text_arr[1][2:]+'运势及穿搭配色'
       
            out_txt.append(title)

            for txt in text_arr[3:]:
                if txt!="":
                    txt=re.sub(r'\n【.】','',txt[2:])
                    txt=re.sub(r'\n','',txt)
                    out_txt.append(txt)


        # print('out_txt:',out_txt)

        return out_txt


    def export_video(self,date_input='20240513',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='no',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='no'):   
        # 图片路径
        image_folder = os.path.join(save_dir,f'{date_input[:4]}-{date_input[4:6]}-{date_input[6:]}')
        # 文字转语音的文本内容
        texts=self.tts_text(date_input=date_input,xls=xls,save=save,save_dir=save_dir,sense_word_judge=sense_word_judge)        
        # texts = [
        #     "2024年05月13日（星期一）甲辰年己巳月丁丑日 运勢及穿搭配色",
        #     "木宝宝建议穿粉色、红色、紫色衣服，佩戴石榴石流苏发钗、红绳手链、紫水晶吊坠以及粉色、红色、紫色的饰品。木宝宝今天有腹背受敌的感觉，凡事多打醒精神，发挥好自己的能力。女性木宝今天桃花运不错。",
        #     "火宝宝建议穿深黄色、棕色、白色以及金色衣服，佩戴金手镯、花丝镶嵌仿点翠耳环、金花发夹以及金色的饰品。火宝宝今天有不少挣钱的好机会，来自于前辈、朋友的介绍。有钱大家一起分，才会朋友更多哟。",
        #     "土宝宝建议穿红色、橙色、紫色、深黄色以及棕色衣服，佩戴蜜蜡手串、金花软簪、小花叶发夹以及棕色的饰品。土宝宝今天不利合作或开展新项目，纷争较多，步调放缓吧。",
        #     "金宝宝建议穿黄色、棕色衣服，佩戴蜜蜡手串、玉石吊坠、金花软簪以及棕色的饰品。金宝宝今天有贵人关照，柳暗花明又一村。工作中的挑战当做新的机会吧！",
        #     "水宝宝建议穿深黄色、棕色、白色以及金色衣服，佩戴蜜蜡手串、金花发夹、玉石吊坠以及金色的饰品。水宝宝今天会有工作、生意上的新消息，变动会给你带来更多的收入。今天也容易邂逅心动对象。"
        # ]
        # 每张图片显示的时间
        


        # print('audio texts:',texts)
        # exit()
        # image_duration = 1.5
        # 转场时间
        transition_duration = 1.0
        # 背景音乐文件路径
        # background_music_file = 'path_to_background_music.mp3'
        # 语音开始播放时间
        audio_start_time = 1.0  # 延迟两秒开始播放语音

       # 每分钟的平均语速（字数） 
        average_speech_speed = 282  # 每分钟282字

        # 生成语音的异步函数
        print('\n正在生成音频...')
        async def generate_audio(text, output_file):
            # 腾讯云TTS配置
            cred = credential.Credential("AKIDFMFvQhmhmeJlzzmKfmfLoEScfWBcsvlN","SimeIkyzqVwEJ4i9QULyNYVEj15znU0L")
            httpProfile = HttpProfile()
            httpProfile.endpoint = "tts.tencentcloudapi.com"

            clientProfile = ClientProfile()
            clientProfile.httpProfile = httpProfile
            client = tts_client.TtsClient(cred, "ap-guangzhou", clientProfile)

            req = models.TextToVoiceRequest()
            params = {
                "Text": text,
                "SessionId": "session-123",
                "ModelType": 1,  # 1-女声，0-男声
                "Volume": 5,
                "Speed": 0,
                "ProjectId": 0,
                "VoiceType": 1001  # 1001-标准女声
            }
            req.from_json_string(json.dumps(params))

            resp = client.TextToVoice(req)
            audio_data = resp.Audio
            
            # 如果返回的是Base64编码的字符串
            if isinstance(audio_data, str):
                import base64
                try:
                    audio_data = base64.b64decode(audio_data)
                except Exception as e:
                    print(f"Base64解码失败: {e}")
                    return
            
            with open(output_file, "wb") as f:
                f.write(audio_data)

        # 生成所有段落的语音文件
        # audio_files = []
        # for i, text in enumerate(texts):
        #     output_file = os.path.join(image_folder,f"output_audio_{i}.mp3")
        #     audio_files.append(output_file)
        #     asyncio.run(generate_audio(text, output_file))


        # 获取图片列表并排序
        images = [img for img in os.listdir(image_folder) if re.match(r'^\d{1}-.*.jpg$',img) or re.match(r'^\d{4}-\d{2}-\d{2}.*抖音封面.jpg$',img)]
        pattern = re.compile(r'^\d{4}-\d{2}-\d{2}.*抖音封面.jpg$')
        cover = None
        for item in images:
            if pattern.match(item):
                cover = item
                break

        # 将符合模式的元素移到列表第一位
        if cover:
            images.remove(cover)

        # 对剩下的元素按数字从小到大排序
        sorted_image_list = sorted(images, key=lambda x: int(re.match(r'(\d+)', x).group()))

        # 将封面元素加到排序后的列表的开头
        if cover:
            sorted_image_list.insert(0, cover)
        # print(sorted_image_list)
        
        # 计算每段文字的时长并创建图片剪辑
        clips = []
        
        for i, (image, text) in enumerate(zip(sorted_image_list, texts)):
            text_length = len(text)
            duration = text_length / (average_speech_speed / 60)  # 计算每段文字的时长
            image_path = os.path.join(image_folder, image)
            clip = ImageClip(image_path).set_duration(duration)
            if i == 0:
                # 将第一张图片的大小调整为720x960
                clip = clip.resize((720, 960))
            clips.append(clip)


       # 添加叠化转场效果
        transition_duration = 1.0  # 转场时间为1秒
        final_clips = [clips[0]]
        for i in range(1, len(clips)):
            transition = clips[i].crossfadein(transition_duration)
            final_clips[-1] = final_clips[-1].crossfadeout(transition_duration)
            final_clips.append(transition)

        # 将所有剪辑合并成一个视频
        video = concatenate_videoclips(final_clips, method="compose")

        # 读取生成的语音音频文件，并合并
        # audio_clips = [AudioFileClip(audio_file) for audio_file in audio_files]
        # text_audios = concatenate_audioclips(audio_clips)

        background_music_file=os.path.join(self.work_dir,'素材','背景音乐','01.mp3')
        # 读取背景音乐文件，并将其裁剪为与视频时长一致
        background_music = AudioFileClip(background_music_file).subclip(0, video.duration)

        # 设置背景音乐的音量，并添加淡入淡出效果
        background_music = background_music.volumex(0.2).audio_fadein(1).audio_fadeout(1)

        # 合并语音音频和背景音乐
        # composite_audio = CompositeAudioClip([background_music, text_audios])

        # 将合成后的音频添加到视频中
        # final_clip = video.set_audio(composite_audio)
        final_clip = video.set_audio(background_music)

        # 生成最终的视频文件
        print('\n正在合成视频...',end='')
        final_clip.write_videofile(os.path.join(image_folder,f"{date_input}-output_video.mp4"), codec="mpeg4", fps=24,bitrate="2000k")

        # 删除中间生成的音频文件
        # for audio_file in audio_files:
        #     os.remove(audio_file)

        print('\n完成')

    def batch_export_video(self,prd=['20240614','20240614'],xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='no',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='no'):
        stime,etime=datetime.strptime(prd[0],'%Y%m%d'),datetime.strptime(prd[1],'%Y%m%d')
        datelist=[]
        while stime<=etime:
            datelist.append(stime.strftime('%Y%m%d'))
            stime+=timedelta(days=1)

        #查看有没有相应的文件夹及图片
        dirs=[]
        for root,all_dirs,fns in os.walk(save_dir):
            for dir in all_dirs:
                dirs.append(dir)

        for nowtime in datelist:            
            if f'{nowtime[:4]}-{nowtime[4:6]}-{nowtime[6:]}' not in dirs:
                print(f'{nowtime} not exists, create it.')
                #生成图片
                self.batch_deal(prd=[nowtime,nowtime],out_put_dir=save_dir,xls=xls)
        
        for nowtime in datelist:
            self.export_video(date_input=nowtime,xls=xls,save=save,save_dir=save_dir,sense_word_judge=sense_word_judge)

        #删除临时文件
        for fn in os.listdir(os.path.dirname(__file__)):
            if fn[-3:]=='mp3':
                os.remove(os.path.join(os.path.dirname(__file__),fn))

class suiBiVideo:
    def __init__(self,work_dir='d:\\工作目录\\ejj',output_dir='E:\\temp\\ejj\\日穿搭'):
        self.work_dir=work_dir
        self.output_dir=output_dir
    
    def read_sb_txt(self,sb_xlsx='d:\\工作目录\\ejj\\运势\\运势2.xlsx'):
        df=pd.read_excel(sb_xlsx,sheet_name='随笔')
        # print(df)
        return df
    
    def date_txt(self,date_input='20240723',sb_xlsx='d:\\工作目录\\ejj\\运势\\运势2.xlsx'):
        try:
            df=self.read_sb_txt(sb_xlsx=sb_xlsx)
            date_txt=df[df['日期']==datetime.strptime(date_input,'%Y%m%d')]['文案'].tolist()[0]
        except Exception as e:
            date_txt=None

        return date_txt
    
    def tts_txt(self,date_input='20240723',sb_xlsx='d:\\工作目录\\ejj\\运势\\运势2.xlsx',output_format='arr'):
        date_txt=self.date_txt(date_input=date_input,sb_xlsx=sb_xlsx)
        if output_format=='arr':
            if date_txt:
                tts_txt=date_txt.split('\n')
                # print(tts_txt)
            else:
                tts_txt=None
        else:
            tts_txt=date_txt
        return tts_txt
    
    def get_suibi_pics(self,date_input='20240723'):
        pics=[]
        for fn in os.listdir(os.path.join(self.output_dir,f'{date_input[:4]}-{date_input[4:6]}-{date_input[6:]}')):
            if re.match(r'\d{8}-s\d{2}.(jpg|JPG|jpeg|JPEG|png|PNG)',fn):
                pics.append(os.path.join(self.output_dir,f'{date_input[:4]}-{date_input[4:6]}-{date_input[6:]}',fn))
        
        return pics
    
    def get_mp3_length(self,file_path):
        audio = MP3(file_path)
        length_in_seconds = audio.info.length
        return length_in_seconds


    def export_video(self,date_input='20240723',sb_xlsx='d:\\工作目录\\ejj\\运势\\运势2.xlsx'):
        output_mp3_file=os.path.join(self.output_dir,f'{date_input[:4]}-{date_input[4:6]}-{date_input[6:]}',date_input+'-suibi.mp3')
        tts_txt=self.tts_txt(date_input=date_input,sb_xlsx=sb_xlsx,output_format='str')
        transition_duration = 1.0
        # 背景音乐文件路径
        # background_music_file = 'path_to_background_music.mp3'
        # 语音开始播放时间
        audio_start_time = 1.0  # 延迟两秒开始播放语音

       # 每分钟的平均语速（字数）
        average_speech_speed = 282  # 每分钟282字

        



        # 获取图片列表并排序
        images = self.get_suibi_pics(date_input=date_input)

        if len(images)>0:
            # 生成语音的异步函数
            print('\n正在生成音频...')
            async def generate_audio(tts_txt, output_mp3_file):
                communicate = edge_tts.Communicate(tts_txt, 'zh-CN-XiaoxiaoNeural')
                await communicate.save(output_mp3_file)
            
            async def generate_mp3_get_length(tts_txt,output_mp3_file):
                await generate_audio(tts_txt,output_mp3_file)
                mp3_length=self.get_mp3_length(output_mp3_file)
                return mp3_length

            mp3_length=asyncio.run(generate_mp3_get_length(tts_txt, output_mp3_file))
            print('mp3 length:',mp3_length)

            time_per_pic=mp3_length/len(images)

            # 计算每段文字的时长并创建图片剪辑
            clips = []
            for i, image in enumerate(images):
                clip = ImageClip(image).set_duration(time_per_pic)
                if i == 0:
                    # 将第一张图片的大小调整为720x960
                    clip = clip.resize(newsize=(720, 960))
                clips.append(clip)

            # 添加叠化转场效果
            transition_duration = 1.0  # 转场时间为1秒
            final_clips = [clips[0]]
            for i in range(1, len(clips)):
                transition = clips[i].crossfadein(transition_duration)
                final_clips[-1] = final_clips[-1].crossfadeout(transition_duration)
                final_clips.append(transition)

            # 将所有剪辑合并成一个视频
            video = concatenate_videoclips(final_clips, method="compose")

            # 读取生成的语音音频文件，并合并
            text_audio = AudioFileClip(output_mp3_file)


            background_music_file=os.path.join(self.work_dir,'素材','背景音乐','02.mp3')
            # 读取背景音乐文件，并将其裁剪为与视频时长一致
            background_music = AudioFileClip(background_music_file).subclip(0, video.duration)

            # 设置背景音乐的音量，并添加淡入淡出效果
            background_music = background_music.volumex(0.2).audio_fadein(1).audio_fadeout(1)

            # 合并语音音频和背景音乐
            composite_audio = CompositeAudioClip([background_music, text_audio])

            # 将合成后的音频添加到视频中
            final_clip = video.set_audio(composite_audio)

            # 生成最终的视频文件
            print('\n正在合成视频...',end='')
            final_clip.write_videofile(os.path.join(self.output_dir,f'{date_input[:4]}-{date_input[4:6]}-{date_input[6:]}',f"{date_input}-suiBi_video.mp4"), codec="mpeg4", fps=24,bitrate="2000k")

            # 删除中间生成的音频文件
            os.remove(output_mp3_file)

            print('\n完成')            

        else:
            print('没有图片或图片未按要求命名。图片应放对应的日期文件夹下，命名规则如：20240728-s01.jpg')
          
class WeekYunCover(ExportImage):
    def __init__(self,work_dir='D:\\工作目录\\ejj'):
        self.work_dir=work_dir
        with open(os.path.join(os.path.dirname(__file__),'configs','fonts.config'),'r',encoding='utf-8') as f:
            self.config=json.load(f)      
    
    def export(self,prd=['20220822','20220828'],save_dir='e:\\temp\\ejj\\日穿搭\\0-每周运势封图'):
        print('正在生成',prd[0]+'-'+prd[1]+'周运封图')
        bg=Image.open(os.path.join(self.work_dir,'素材','周运底图','周运封图竖.jpg'))
        txt=prd[0][:4]+'年'+prd[0][4:6]+'月'+prd[0][6:]+'日'+'-'+prd[1][:4]+'年'+prd[1][4:6]+'月'+prd[1][6:]+'日'
        draw=ImageDraw.Draw(bg)
        draw.text((210,80),text=txt,fill='#968351',font=self.font('字由文艺黑体',20))

        if not os.path.exists(save_dir):
            os.makedirs(save_dir)

        bg.save(os.path.join(save_dir,prd[0]+'-'+prd[1]+'周运封图.jpg'),quality=95,subsampling=0)

        print('完成')

class CustomError(Exception):
    def __init__(self, message):
        self.message = message

class Vividict(dict):
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

if __name__=='__main__':
    # p=ExportImage(work_dir='d:\\工作目录\\ejj')
    # pic=p.draw_img(date_input='20250320',wx='木',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',exp_txt='no',dec_name_only='no')
    # pic=p.draw_dec_cover(date_gz='乙巳年庚子月庚子日',date_txt='2025年3月20日',weekday='星期五')
    # pic['dec_cover'].show()
    
    #######################  一周日穿搭配色文案 + 周运封图   #######################
    # p=ExportWeekYunTxt(work_dir='/home/jack/Nutstore Files')
    # week_txts=ExportWeekYunTxt(work_dir='d:\\工作目录\\ejj')
    # p.all_date_wx(prd=['20250131','20250131'],xls='/home/jack/Nutstore Files/运势/运势.xlsx')

    ########################  导出随笔视频 ##########################
    #导出图片
    # p=suiBiVideo(work_dir='d:\\工作目录\\ejj',output_dir='E:\\temp\\ejj\\日穿搭')
    # p.read_sb_txt(sb_xlsx='d:\\工作目录\\ejj\\运势\\运势2.xlsx')
    # p.tts(date_input='20240723',sb_xlsx='d:\\工作目录\\ejj\\运势\\运势2.xlsx')
    # p.get_suibi_pics(date_input='20240717')
    # p.export_video(date_input='20240717',sb_xlsx='d:\\工作目录\\ejj\\运势\\运势2.xlsx')


     ######################## 单个五行 ##########################

    # week_pic=ExportImage(work_dir='d:\\工作目录\\ejj')
    # res=week_pic.draw_img(date_input='20250423',wx='木',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',exp_txt='no',dec_name_only='no')
    # # print(res['draw_img_data'])
    # res['draw_img_data'][0].show()

    # ########################  导出视频 ##########################
    # #导出图片
    # week_pic=ExportImage(work_dir='d:\\工作目录\\ejj')
    week_pic=ExportImage(work_dir='D:\\NutsStore')
    # week_pic=ExportImage(work_dir='/home/jack/Nutstore Files')
    # dec_txt=week_pic.batch_deal(prd=['20250423','20250423'],out_put_dir='e:\\temp\\ejj\\日穿搭',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx')
    # dec_txt=week_pic.batch_deal(prd=['20250730','20250730'],out_put_dir='/media/jack/data/temp/ejj/日穿搭',xls='/home/jack/Nutstore Files/运势/运势.xlsx')
    dec_txt=week_pic.batch_deal(prd=['20250730','20250730'],out_put_dir='d:\\temp\\ejj\\日穿搭',xls='D:\\NutsStore\\运势\\运势.xlsx')
    # # #导出文本
    # week_txts=ExportWeekYunTxt(work_dir='d:\\工作目录\\ejj',import_dec_dic=dec_txt)
    # week_txts=ExportWeekYunTxt(work_dir='/home/jack/Nutstore Files',import_dec_dic=dec_txt)
    week_txts=ExportWeekYunTxt(work_dir='D:\\NutsStore',import_dec_dic=dec_txt)
    # week_txts.all_date_wx(prd=['20250423','20250423'],xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='yes',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='yes')
    # week_txts.all_date_wx(prd=['20250730','20250730'],xls='/home/jack/Nutstore Files/运势/运势.xlsx',save='yes',save_dir='/media/jack/data/temp/ejj/日穿搭')
    week_txts.all_date_wx(prd=['20250730','20250730'],xls='D:\\NutsStore\\运势\\运势.xlsx',save='yes',save_dir='d:\\temp\\ejj\\日穿搭')
    # #导出视频
    # videos=videoClips(work_dir='/home/jack/Nutstore Files',import_dec_dic=dec_txt)
    videos=videoClips(work_dir='D:\\NutsStore',import_dec_dic=dec_txt)
    # videos.batch_export_video(prd=['20240614','20240614'],xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='no',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='no')
    # videos.batch_export_video(prd=['20250730','20250730'],xls='/home/jack/Nutstore Files/运势/运势.xlsx',save='no',save_dir='/media/jack/data/temp/ejj/日穿搭',sense_word_judge='no')
    videos.batch_export_video(prd=['20250730','20250730'],xls='D:\\NutsStore\\运势\\运势.xlsx',save='no',save_dir='d:\\temp\\ejj\\日穿搭',sense_word_judge='no')
   
      #######################  导出一周日穿搭文案   #######################
    # p=ExportWeekYunTxt(work_dir='D:\\工作目录\\ejj')
    # # p=ExportWeekYunTxt(work_dir='/home/jack/Nutstore Files')
    # # res=p.all_wx_txt(date_input='20240614',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='yes',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='no')
    # # res=p.all_wx_txt(date_input='20240725',xls='/Users/Jack/Nutstore Files/运势/运势2.xlsx',save='yes',save_dir='~/temp/ejj/日穿搭',sense_word_judge='no')
    # # p.tts_text(date_input='20240513',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='no',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='no')
    # # print(res)
    # # p.douyin(res['douyin_txt'])
    # # p.douyin(txt_lst='')
    # # print(res)
    # res=p.all_date_wx(prd=['20250320','20250320'],xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='yes',save_dir='e:\\temp\\ejj\\日穿搭')
    # res=p.all_date_wx(prd=['20250131','20250131'],xls='/home/jack/Nutstore Files/运势/运势.xlsx',save='yes',save_dir='/media/jack/data/temp/ejj/日穿搭')
    
    # print(res)
    # p.all_date_wx(prd=['20240725','20240725'],xls='/Users/Jack/Nutstore Files/运势/运势2.xlsx',save='yes',save_dir='/Users/Jack/temp/ejj/日穿搭')
    # p.export_video(date_input='20240614',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx',save='no',save_dir='e:\\temp\\ejj\\日穿搭',sense_word_judge='no')


    #######################  导出周运封图   #######################
    # p=WeekYunCover(work_dir='D:\\工作目录\\ejj')
    # p.export(prd=['20220822','20220828'],save_dir='e:\\temp\\ejj\\日穿搭\\0-每周运势封图')





    # p=WeekYun() 
    # df=p.wuxing(date_input='20220822',wx='木',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx')
    # print(df)


    # p=ExportImage()
    # res=p.draw_img(date_input='20220828',wx='木',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx')
    # res.show()
    # res=p.batch_deal(prd=['20240912','20240912'],out_put_dir='e:\\temp\\ejj\日穿搭',xls='d:\\工作目录\\ejj\\运势\\运势.xlsx')
    # print(res)
